package cn.edu.zufe.mjt;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;

/**
 * @author 蒙锦涛
 * @date 2025/5/28
 * @description 自定义的锁实现
 */

public class MyLock {

    AtomicBoolean flag = new AtomicBoolean(false);

    Thread owner = null;

    AtomicReference<Node> head = new AtomicReference<>(new Node());

    AtomicReference<Node> tail = new AtomicReference<>(head.get());

    void lock() {
        // 基于 CAS 实现一个锁，如果能从 false 改为 true，说明没有别的线程在占用锁，则成功获取锁
        // 当没有这个if条件时，这个锁就变成了公平锁。因为后来的线程一定会插入链表里，没有插队的机会了
//        if (flag.compareAndSet(false, true)) {
//            // 拿到锁之后，更新持有者并返回
//            System.out.println(Thread.currentThread().getName() + "直接拿到锁");
//            owner = Thread.currentThread();
//            return;
//        }

        // 没有拿到锁，需要安全的把线程放入尾结点
        Node current = new Node();
        current.thread = Thread.currentThread();
        while (true) {
            Node currentTail = tail.get(); // 每次尝试之前都拿到尾结点，防止因其他线程修改而导致的不一致
            // 尝试把当前线程放入尾结点
            if (tail.compareAndSet(currentTail, current)) {
                // 当成功放入后，才算成功，否则需要重新尝试
                System.out.println(Thread.currentThread().getName() + "加入到了链表尾");
                current.pre = currentTail;
                currentTail.next = current;
                break;
            }
        }

        // 放入尾结点后就需要阻塞等待，直到被唤醒
        while (true) {
            // condition
            // head --> A --> B  当 A的线程 持有锁了后，那 A的线程 之前的就不需要了，此时 A 节点就要变成 head 节点
            // 每次只唤醒 head 的下一个节点的线程，且当被唤醒了之后，head 就指向它
            if (current.pre == head.get() && flag.compareAndSet(false, true)) {
                owner = Thread.currentThread();
                head.set(current); // 一定是安全的，一定是持有锁的线程进行的操作
                // 断掉当前节点的前驱节点
                current.pre.next = null;
                current.pre = null;
                // 断掉后才能放回，表示真正拿到了锁
                System.out.println(Thread.currentThread().getName() + "被唤醒之后拿到了锁");
                return;
            }
            // 先判断能否获得锁再阻塞，避免直接阻塞没有其他线程唤醒的情况
            LockSupport.park();
        }

    }

    void unlock() {
        if (Thread.currentThread() != this.owner) {
            throw new IllegalStateException("当前线程不是锁的拥有者，不能释放锁");
        }
        // 如果触发了释放锁，那么一定是持有锁的线程触发的
        // 持有锁的情况：1 没有将自己放入链表，直接拿到了锁； 2 已经放入链表，且把自己放到了 head 上
        // 这两种情况都可以理解为只需要唤醒head的下一个节点的线程即可

        Node headNode = head.get();
        Node next = headNode.next;
        flag.set(false); // 不需要 CAS
        // 解锁之后，下面的步骤就会发生竞争了
        if (next != null) {
            System.out.println(Thread.currentThread().getName() + "唤醒了" + next.thread.getName() + "线程");
            LockSupport.unpark(next.thread);
        }
    }



    static class Node {
        Node pre;
        Node next;
        Thread thread;
    }
}
